<script lang="ts" setup>
import { computed, onMounted, reactive } from "vue";

type Props = {
    duration: number | string;
    startText: string;
    changeText: string;
    endText: string;
    keepRunning: boolean;
    uniqueKey: string;
};

type State = {
    leftTime: number;
    disabled: boolean;
    timer: number | undefined;
    uniqueKey: string;
};

type Emits = {
    (e: "update:disabled", disabled: boolean): void;
    (e: "update:text", text: string): void;
    (e: "start"): void;
    (e: "change", text: string): void;
    (e: "end"): void;
};

const props = withDefaults(defineProps<Props>(), {
    duration: 60,
    startText: "获取验证码",
    changeText: "{time}秒重新获取",
    endText: "重新获取",
    keepRunning: false,
    uniqueKey: "",
});
const emits = defineEmits<Emits>();
const state: State = reactive({
    leftTime: 0,
    disabled: false,
    timer: undefined,
    uniqueKey: "",
});

const updateText = (text: string) => {
    emits("change", text);
    emits("update:text", text);
};

const setStatus = (disabled: boolean) => {
    state.disabled = disabled;
    emits("update:disabled", disabled);
};

const setStorage = () => {
    if (state.uniqueKey && props.keepRunning) {
        const key = `caih-captcha[${state.uniqueKey}]`;
        const params = { timestamp: Date.now(), left: state.leftTime };
        localStorage.setItem(key, JSON.stringify(params));
    }
};

const loop = () => {
    const text = props.changeText.replace("{time}", state.leftTime.toString());
    updateText(text);
    state.leftTime--;

    if (state.leftTime >= 0) {
        state.timer = setTimeout(loop, 1000);
        setStorage();
    } else {
        const key = `caih-captcha[${state.uniqueKey}]`;
        localStorage.removeItem(key);
        emits("end");
        setStatus(false);
        updateText(props.endText);
    }
};

const start = () => {
    if (state.disabled) return;

    state.leftTime = Number(props.duration);
    emits("start");
    setStatus(true);
    loop();
};

const reset = () => {
    clearTimeout(state.timer);
    state.leftTime = 0;
    emits("end");
    setStatus(false);
    updateText(props.startText);
};

onMounted(() => {
    updateText(props.startText);
    if (isNaN(props.duration as number)) {
        throw new Error("倒计时持续时间类型为正整数");
    }

    state.uniqueKey = props.uniqueKey;
    if (state.uniqueKey && props.keepRunning) {
        try {
            const key = `caih-captcha[${state.uniqueKey}]`;
            const { timestamp, left } = JSON.parse(localStorage.getItem(key)!);
            const diff = timestamp + left * 1000 - Date.now();
            if (diff > 0) {
                state.leftTime = (diff / 1000) | 0;
                emits("start");
                setStatus(true);
                loop();
            }
            localStorage.removeItem(key);
        } catch (error) {
            console.log("component[captcha] parse json catch error.", error);
        }
    }
});
defineExpose({ start, reset, disabled: computed(() => state.disabled) });
</script>
